// Copyright 2019 Google LLC.
#include "include/core/SkTypeface.h"
#include "modules/skparagraph/include/FontCollection.h"
#include "modules/skparagraph/include/Paragraph.h"
#include "modules/skparagraph/src/ParagraphImpl.h"
#include <native_drawing/drawing_font_collection.h>
// #include "modules/skshaper/include/SkShaper.h"
#include "modules/skparagraph/include/TypefaceFontProvider.h"

namespace skia {
namespace textlayout {

//std::shared_ptr<OH_Drawing_FontCollection> FontCollection::fFontCollectionOHOS = nullptr;
std::atomic<uint32_t> FontCollection::fCustomFontNumFromMakeFromData{0};

bool FontCollection::FamilyKey::operator==(const FontCollection::FamilyKey& other) const {
    return fFamilyNames == other.fFamilyNames &&
           fFontStyle == other.fFontStyle &&
           fFontArguments == other.fFontArguments;
}

size_t FontCollection::FamilyKey::Hasher::operator()(const FontCollection::FamilyKey& key) const {
    size_t hash = 0;
    for (const SkString& family : key.fFamilyNames) {
        hash ^= std::hash<std::string>()(family.c_str());
    }
    return hash ^
           std::hash<uint32_t>()(key.fFontStyle.weight()) ^
           std::hash<uint32_t>()(key.fFontStyle.slant()) ^
           std::hash<std::optional<FontArguments>>()(key.fFontArguments);
}

FontCollection::FontCollection()
        : fEnableFontFallback(true)
//        , fEnableSystemThemeFont(useSystemThemeFont)
        , fDefaultFamilyNames({SkString(DEFAULT_FONT_FAMILY)}) {
    // Use Global Instance to use System Theme Font
    // never release the OH_Drawing_GetFontCollectionGlobalInstance
//    if (fEnableSystemThemeFont) {
//        fFontCollectionOHOS = OH_Drawing_GetFontCollectionGlobalInstance();
//    } else {
//        fFontCollectionOHOS = OH_Drawing_CreateSharedFontCollection();
//    }
}

FontCollection::~FontCollection() {
//    if (!fEnableSystemThemeFont) {
//        OH_Drawing_DestroyFontCollection(fFontCollectionOHOS);
//    }
//    // @todo is this safe and correct?
//    if (fFontCollectionOHOS && fFontCollectionOHOS.use_count() == 1) {
//        fFontCollectionOHOS.reset();
//    }
}

size_t FontCollection::getFontManagersCount() const { return this->getFontManagerOrder().size(); }

void FontCollection::setAssetFontManager(sk_sp<SkFontMgr> font_manager) {
    fAssetFontManager = font_manager;
    
    auto* provider = dynamic_cast<skia::textlayout::TypefaceFontProvider*>(fAssetFontManager.get());

    if (provider) {
        provider->setFontCollection(this);
    } else {
        SkDebugf("setAssetFontManager: font_manager is not TypefaceFontProvider, registered font may not work\n");
        return;
    }

}

void FontCollection::setDynamicFontManager(sk_sp<SkFontMgr> font_manager) {
    fDynamicFontManager = font_manager;
}

void FontCollection::setTestFontManager(sk_sp<SkFontMgr> font_manager) {
    fTestFontManager = font_manager;
}

void FontCollection::setDefaultFontManager(sk_sp<SkFontMgr> fontManager,
                                           const char defaultFamilyName[]) {
    fDefaultFontManager = std::move(fontManager);
    fDefaultFamilyNames.emplace_back(defaultFamilyName);
}

void FontCollection::setDefaultFontManager(sk_sp<SkFontMgr> fontManager,
                                           const std::vector<SkString>& defaultFamilyNames) {
    fDefaultFontManager = std::move(fontManager);
    fDefaultFamilyNames = defaultFamilyNames;
}

void FontCollection::setDefaultFontManager(sk_sp<SkFontMgr> fontManager) {
    fDefaultFontManager = fontManager;
}

// Return the available font managers in the order they should be queried.
std::vector<sk_sp<SkFontMgr>> FontCollection::getFontManagerOrder() const {
    std::vector<sk_sp<SkFontMgr>> order;
    if (fDynamicFontManager) {
        order.push_back(fDynamicFontManager);
    }
    if (fAssetFontManager) {
        order.push_back(fAssetFontManager);
    }
    if (fTestFontManager) {
        order.push_back(fTestFontManager);
    }
    if (fDefaultFontManager && fEnableFontFallback) {
        order.push_back(fDefaultFontManager);
    }
    return order;
}

std::vector<sk_sp<SkTypeface>> FontCollection::findTypefaces(const std::vector<SkString>& familyNames, SkFontStyle fontStyle) {
    return findTypefaces(familyNames, fontStyle, std::nullopt);
}

std::vector<sk_sp<SkTypeface>> FontCollection::findTypefaces(const std::vector<SkString>& familyNames, SkFontStyle fontStyle, const std::optional<FontArguments>& fontArgs) {
    // Look inside the font collections cache first
//     FamilyKey familyKey(familyNames, fontStyle, fontArgs);
    // not support for fontArgs
    FamilyKey familyKey(familyNames, fontStyle, std::nullopt);
     auto found = fTypefaces.find(familyKey);
     if (found) {
         return *found;
     }

     std::vector<sk_sp<SkTypeface>> typefaces;
     for (const SkString& familyName : familyNames) {
         sk_sp<SkTypeface> match = matchTypeface(familyName, fontStyle);
//         if (match && fontArgs) {
//             match = fontArgs->CloneTypeface(match);
//         }
         if (match) {
             typefaces.emplace_back(std::move(match));
         }
     }

     if (typefaces.empty()) {
         sk_sp<SkTypeface> match;
         for (const SkString& familyName : fDefaultFamilyNames) {
             match = matchTypeface(familyName, fontStyle);
             if (match) {
                 break;
             }
         }
         if (!match) {
             for (const auto& manager : this->getFontManagerOrder()) {
                 match = manager->legacyMakeTypeface(nullptr, fontStyle);
                 if (match) {
                     break;
                 }
             }
         }
         if (match) {
             typefaces.emplace_back(std::move(match));
         }
     }

     fTypefaces.set(familyKey, typefaces);
     return typefaces;
}

sk_sp<SkTypeface> FontCollection::matchTypeface(const SkString& familyName, SkFontStyle fontStyle) {
     for (const auto& manager : this->getFontManagerOrder()) {
         sk_sp<SkFontStyleSet> set(manager->matchFamily(familyName.c_str()));
         if (!set || set->count() == 0) {
             continue;
         }

         sk_sp<SkTypeface> match(set->matchStyle(fontStyle));
         if (match) {
             return match;
         }
     }

     return nullptr;
}

// Find ANY font in available font managers that resolves the unicode codepoint
sk_sp<SkTypeface> FontCollection::defaultFallback(SkUnichar unicode, SkFontStyle fontStyle, const SkString& locale) {
    RENDER_UNIMPLEMENTED;
    return nullptr;
//     for (const auto& manager : this->getFontManagerOrder()) {
//         std::vector<const char*> bcp47;
//         if (!locale.isEmpty()) {
//             bcp47.push_back(locale.c_str());
//         }
//         sk_sp<SkTypeface> typeface(manager->matchFamilyStyleCharacter(
//                 nullptr, fontStyle, bcp47.data(), bcp47.size(), unicode));
//         if (typeface != nullptr) {
//             return typeface;
//         }
//     }
//     return nullptr;
}

sk_sp<SkTypeface> FontCollection::defaultFallback() {
    RENDER_UNIMPLEMENTED;
    return nullptr;
//     if (fDefaultFontManager == nullptr) {
//         return nullptr;
//     }
//     for (const SkString& familyName : fDefaultFamilyNames) {
//         sk_sp<SkTypeface> match = fDefaultFontManager->matchFamilyStyle(familyName.c_str(),
//                                                                         SkFontStyle());
//         if (match) {
//             return match;
//         }
//     }
//     return nullptr;
}


void FontCollection::disableFontFallback() {
    fEnableFontFallback = false;
    // OH can disable font fallback but did not provide the enable api
//    OH_Drawing_DisableFontCollectionFallback(getFontCollectionOHOS().get());
}
void FontCollection::enableFontFallback() { fEnableFontFallback = true; }

void FontCollection::clearCaches() {
    fParagraphCache.reset();
    fTypefaces.reset();
    OH_Drawing_ClearFontCaches(getFontCollectionOHOS().get());
//     SkShaper::PurgeCaches();
}

}  // namespace textlayout
}  // namespace skia
